home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / win / tclWinNotify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  7.0 KB  |  326 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclWinNotify.c --
  3.  *
  4.  *    This file contains Windows-specific procedures for the notifier,
  5.  *    which is the lowest-level part of the Tcl event loop.  This file
  6.  *    works together with ../generic/tclNotify.c.
  7.  *
  8.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tclWinNotify.c 1.17 97/05/23 10:48:44
  14.  */
  15.  
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18. #include <winsock.h>
  19.  
  20. /*
  21.  * The follwing static indicates whether this module has been initialized.
  22.  */
  23.  
  24. static int initialized = 0;
  25.  
  26. #define INTERVAL_TIMER 1        /* Handle of interval timer. */
  27.  
  28. /*
  29.  * The following static structure contains the state information for the
  30.  * Windows implementation of the Tcl notifier.
  31.  */
  32.  
  33. static struct {
  34.     HWND hwnd;            /* Messaging window. */
  35.     int timeout;        /* Current timeout value. */
  36.     int timerActive;        /* 1 if interval timer is running. */
  37. } notifier;
  38.  
  39. /*
  40.  * Static routines defined in this file.
  41.  */
  42.  
  43. static void        InitNotifier(void);
  44. static void        NotifierExitHandler(ClientData clientData);
  45. static LRESULT CALLBACK    NotifierProc(HWND hwnd, UINT message,
  46.                 WPARAM wParam, LPARAM lParam);
  47. static void        UpdateTimer(int timeout);
  48.  
  49. /*
  50.  *----------------------------------------------------------------------
  51.  *
  52.  * InitNotifier --
  53.  *
  54.  *    Initializes the notifier window.
  55.  *
  56.  * Results:
  57.  *    None.
  58.  *
  59.  * Side effects:
  60.  *    Creates a new notifier window and window class.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64.  
  65. static void
  66. InitNotifier(void)
  67. {
  68.     WNDCLASS class;
  69.  
  70.     initialized = 1;
  71.     notifier.timerActive = 0;
  72.     class.style = 0;
  73.     class.cbClsExtra = 0;
  74.     class.cbWndExtra = 0;
  75.     class.hInstance = TclWinGetTclInstance();
  76.     class.hbrBackground = NULL;
  77.     class.lpszMenuName = NULL;
  78.     class.lpszClassName = "TclNotifier";
  79.     class.lpfnWndProc = NotifierProc;
  80.     class.hIcon = NULL;
  81.     class.hCursor = NULL;
  82.  
  83.     if (!RegisterClass(&class)) {
  84.     panic("Unable to register TclNotifier window class");
  85.     }
  86.     notifier.hwnd = CreateWindow("TclNotifier", "TclNotifier", WS_TILED,
  87.         0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
  88.     Tcl_CreateExitHandler(NotifierExitHandler, NULL);
  89. }
  90.  
  91. /*
  92.  *----------------------------------------------------------------------
  93.  *
  94.  * NotifierExitHandler --
  95.  *
  96.  *    This function is called to cleanup the notifier state before
  97.  *    Tcl is unloaded.
  98.  *
  99.  * Results:
  100.  *    None.
  101.  *
  102.  * Side effects:
  103.  *    Destroys the notifier window.
  104.  *
  105.  *----------------------------------------------------------------------
  106.  */
  107.  
  108. static void
  109. NotifierExitHandler(
  110.     ClientData clientData)    /* Old window proc */
  111. {
  112.     initialized = 0;
  113.     if (notifier.hwnd) {
  114.     KillTimer(notifier.hwnd, INTERVAL_TIMER);
  115.     DestroyWindow(notifier.hwnd);
  116.     UnregisterClass("TclNotifier", TclWinGetTclInstance());
  117.     notifier.hwnd = NULL;
  118.     }
  119. }
  120.  
  121. /*
  122.  *----------------------------------------------------------------------
  123.  *
  124.  * UpdateTimer --
  125.  *
  126.  *    This function starts or stops the notifier interval timer.
  127.  *
  128.  * Results:
  129.  *    None.
  130.  *
  131.  * Side effects:
  132.  *    None.
  133.  *
  134.  *----------------------------------------------------------------------
  135.  */
  136.  
  137. void
  138. UpdateTimer(
  139.     int timeout)        /* ms timeout, 0 means cancel timer */
  140. {
  141.     notifier.timeout = timeout;
  142.     if (timeout != 0) {
  143.     notifier.timerActive = 1;
  144.     SetTimer(notifier.hwnd, INTERVAL_TIMER,
  145.             (unsigned long) notifier.timeout, NULL);
  146.     } else {
  147.     notifier.timerActive = 0;
  148.     KillTimer(notifier.hwnd, INTERVAL_TIMER);
  149.     }
  150. }
  151.  
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * Tcl_SetTimer --
  156.  *
  157.  *    This procedure sets the current notifier timer value.  The
  158.  *    notifier will ensure that Tcl_ServiceAll() is called after
  159.  *    the specified interval, even if no events have occurred.
  160.  *
  161.  * Results:
  162.  *    None.
  163.  *
  164.  * Side effects:
  165.  *    Replaces any previous timer.
  166.  *
  167.  *----------------------------------------------------------------------
  168.  */
  169.  
  170. void
  171. Tcl_SetTimer(
  172.     Tcl_Time *timePtr)        /* Maximum block time, or NULL. */
  173. {
  174.     UINT timeout;
  175.  
  176.     if (!initialized) {
  177.     InitNotifier();
  178.     }
  179.  
  180.     if (!timePtr) {
  181.     timeout = 0;
  182.     } else {
  183.     /*
  184.      * Make sure we pass a non-zero value into the timeout argument.
  185.      * Windows seems to get confused by zero length timers.
  186.      */
  187.     timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
  188.     if (timeout == 0) {
  189.         timeout = 1;
  190.     }
  191.     }
  192.     UpdateTimer(timeout);
  193. }
  194.  
  195. /*
  196.  *----------------------------------------------------------------------
  197.  *
  198.  * NotifierProc --
  199.  *
  200.  *    This procedure is invoked by Windows to process the timer
  201.  *    message whenever we are using an external dispatch loop.
  202.  *
  203.  * Results:
  204.  *    A standard windows result.
  205.  *
  206.  * Side effects:
  207.  *    Services any pending events.
  208.  *
  209.  *----------------------------------------------------------------------
  210.  */
  211.  
  212. static LRESULT CALLBACK
  213. NotifierProc(
  214.     HWND hwnd,
  215.     UINT message,
  216.     WPARAM wParam,
  217.     LPARAM lParam)
  218. {
  219.  
  220.     if (message != WM_TIMER) {
  221.     return DefWindowProc(hwnd, message, wParam, lParam);
  222.     }
  223.     
  224.     /*
  225.      * Process all of the runnable events.
  226.      */
  227.  
  228.     Tcl_ServiceAll();
  229.     return 0;
  230. }
  231.  
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * Tcl_WaitForEvent --
  236.  *
  237.  *    This function is called by Tcl_DoOneEvent to wait for new
  238.  *    events on the message queue.  If the block time is 0, then
  239.  *    Tcl_WaitForEvent just polls the event queue without blocking.
  240.  *
  241.  * Results:
  242.  *    Returns -1 if a WM_QUIT message is detected, returns 1 if
  243.  *    a message was dispatched, otherwise returns 0.
  244.  *
  245.  * Side effects:
  246.  *    Dispatches a message to a window procedure, which could do
  247.  *    anything.
  248.  *
  249.  *----------------------------------------------------------------------
  250.  */
  251.  
  252. int
  253. Tcl_WaitForEvent(
  254.     Tcl_Time *timePtr)        /* Maximum block time, or NULL. */
  255. {
  256.     MSG msg;
  257.     int timeout;
  258.  
  259.     if (!initialized) {
  260.     InitNotifier();
  261.     }
  262.  
  263.     /*
  264.      * Only use the interval timer for non-zero timeouts.  This avoids
  265.      * generating useless messages when we really just want to poll.
  266.      */
  267.  
  268.     if (timePtr) {
  269.     timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
  270.     } else {
  271.     timeout = 0;
  272.     }
  273.     UpdateTimer(timeout);
  274.     
  275.     if (!timePtr || (timeout != 0)
  276.         || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
  277.     if (!GetMessage(&msg, NULL, 0, 0)) {
  278.  
  279.         /*
  280.          * The application is exiting, so repost the quit message
  281.          * and start unwinding.
  282.          */
  283.  
  284.         PostQuitMessage(msg.wParam);
  285.         return -1;
  286.     }
  287.  
  288.     /*
  289.      * Handle timer expiration as a special case so we don't
  290.      * claim to be doing work when we aren't.
  291.      */
  292.  
  293.     if (msg.message == WM_TIMER && msg.hwnd == notifier.hwnd) {
  294.         return 0;
  295.     }
  296.  
  297.     TranslateMessage(&msg);
  298.     DispatchMessage(&msg);
  299.     return 1;
  300.     }
  301.     return 0;
  302. }
  303.  
  304. /*
  305.  *----------------------------------------------------------------------
  306.  *
  307.  * Tcl_Sleep --
  308.  *
  309.  *    Delay execution for the specified number of milliseconds.
  310.  *
  311.  * Results:
  312.  *    None.
  313.  *
  314.  * Side effects:
  315.  *    Time passes.
  316.  *
  317.  *----------------------------------------------------------------------
  318.  */
  319.  
  320. void
  321. Tcl_Sleep(ms)
  322.     int ms;            /* Number of milliseconds to sleep. */
  323. {
  324.     Sleep(ms);
  325. }
  326.